home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / tex / sed15.zip / SEDEXEC.C < prev    next >
C/C++ Source or Header  |  1991-09-27  |  20KB  |  539 lines

  1. /*
  2.  * sedexec.c -- execute compiled form of stream editor commands
  3.  *
  4.  * The single entry point of this module is the function execute(). It may take
  5.  * a string argument (the name of a file to be used as text)  or the argument
  6.  * NULL which tells it to filter standard input. It executes the compiled
  7.  * commands in cmds[] on each line in turn. The function command() does most
  8.  * of the work. Match() and advance() are used for matching text against
  9.  * precompiled regular expressions and dosub() does right-hand-side
  10.  * substitution.  Getline() does text input; readout() and smemcmp() are
  11.  * output and string-comparison utilities.
  12.  *
  13.  * ==== Written for the GNU operating system by Eric S. Raymond ====
  14.  * v1.2, 14 Jul 91
  15.  * From: mdlawler@bsu-cs.bsu.edu (Michael D. Lawler)
  16.  * Change the line in sedexec.c from
  17.  *    static int delete;
  18.  * to
  19.  *   static int delete = TRUE;
  20.  * and let me know if it still compiles ok under TurboC 2.0.
  21.  * I made this change which was suggested by Mark Adler
  22.  * and it made sed work fine under BC++ 2.0.
  23.  *
  24.  * Toad Hall:  Compiles just fine in TC 2.0.
  25.  *
  26.  * v1.1, 19 Jun 91
  27.  * Toad Hall Tweak for TC v2.0
  28.  * See VERSION.NOT for details
  29.  * modified September 91 by hh see notes in sedcomp.c
  30.  */
  31.  
  32. #ifdef OTHER /*hh 14*/
  33. #include "compiler.h"
  34. #include "debug.h"
  35. #endif
  36. #ifdef LATTICE
  37. #define void int
  38. #endif
  39.  
  40. #include <stdio.h>    /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
  41. #include <ctype.h>    /* for isprint(), isdigit(), toascii() macros */
  42. #include "sed.h"    /* command type structures & miscellaneous* constants */
  43.  
  44. #ifdef __TURBOC__        /* v1.1 */
  45. #include <string.h>
  46. #include <stdlib.h>        /* exit() */
  47. static char    *getline(register char *buf);
  48. static int    selected(sedcmd *ipc);
  49. static void    command(sedcmd *ipc);
  50. static void     readout(void);
  51. static int    match(char *expbuf, int gf);
  52. static int    advance(register char *lp, register char *ep);
  53. static void    dosub(char *rhsbuf);
  54. static char    *place(char *asp,char *al1,char *al2);
  55. static void    listto(register char *p1, FILE *fp);
  56. static int    substitute(sedcmd *ipc);
  57. /* v1.1 renamed this so it wouldn't conflict with TC's memcmp() */
  58. static int    smemcmp(register char *a, register char *b, int count);
  59. #else    /* !PROTO */
  60. extern char    *strcpy();    /* used in dosub */
  61.     char    *getline();    /* input-getting functions */
  62.     void    command(), readout();
  63.     void    dosub();    /* for if we find a match */
  64.     char            *place();
  65. #endif    /* ?PROTO */
  66.  
  67. /***** shared variables imported from the main ******/
  68.  
  69. /* main data areas */
  70. extern char    linebuf[];    /* current-line buffer */
  71. extern sedcmd    cmds[];        /* hold compiled commands */
  72. extern long    linenum[];    /* numeric-addresses table */
  73.  
  74. /* miscellaneous shared variables */
  75. extern int    nflag;        /* -n option flag */
  76. extern int    eargc;        /* scratch copy of argument count */
  77. extern sedcmd    *pending;    /* ptr to command waiting to be executed */
  78. extern char    bits[];        /* the bits table */
  79.  
  80. #define MAXHOLD        MAXBUF    /* size of the hold space */
  81. #define GENSIZ        MAXBUF    /* maximum genbuf size */
  82. #define TRUE            1
  83. #define FALSE            0
  84. #define JUMPLIMIT  50  /*max branches before inf loop*/
  85. #define ABORT2(msg,arg) (fprintf(stderr,msg,arg),exit(2))
  86. #define ISWCHAR(c) (isalnum(c)||c=='_')
  87. #define Copy(to,from,ep) {char *it=to,*ix=from;while(*it++=*ix++);ep=it-1;}
  88. static char     INFLOOP[]= "sed: infinite branch loop at line %ld\n";
  89. static char    LTLMSG[] = "sed: line too long at line %ld\n";
  90. static char     FILEBAD[]= "sed: cannot open %s\n";
  91. static char     REBAD[]=   "sed: RE bad code %x\n";
  92. static char     APPERR[]=  "sed: too many appends after line %ld\n";
  93. static char     APPLNG[]=  "sed: append too long after line %ld\n";
  94. static char     READERR[]= "sed: too many reads after line %ld\n";
  95. static char    *spend;        /* current end-of-line-buffer pointer */
  96. static long    lnum = 0L;    /* current source line number */
  97.  
  98. /* append buffer maintenance */
  99. static sedcmd  *appends[MAXAPPENDS];    /* array of ptrs to a,i,c commands */
  100. static sedcmd **aptr = appends;            /* ptr to current append */
  101.  
  102. /* genbuf and its pointers and misc pointers*/
  103. static char    genbuf[GENSIZ];
  104. static long     pcnt[MAXPLUS]; /*holder for count downs*/
  105.  
  106. /* command-logic flags */
  107. static int    lastline;    /* do-line flag */
  108. static int    jump, jumpcnt;    /* jump set and loop counter */
  109. static int    delete = FALSE;    /* delete command flag *//*hh 2*/
  110. static int      cdswitch=FALSE; /*in midst of D command*/
  111.  
  112. /* tagged-pattern tracking */
  113. static char    *bracend[MAXTAGS+1];    /* tagged pattern start pointers */
  114. static char    *brastart[MAXTAGS+1];    /* tagged pattern end pointers */
  115.  
  116. /* execute the compiled commands in cmds[] on a file */
  117. void execute(file) char    *file;{    /* name of text source file to be edited */
  118.     register sedcmd *ipc;    /* ptr to current command */
  119.     if (file&&!freopen(file, "rt", stdin)) ABORT2(FILEBAD,file);
  120.     /* here's the main command-execution loop */
  121.         while(pending||cdswitch||(spend=getline(linebuf))){  /* v1.5*/
  122.         ipc =pending? pending:cmds;
  123.         delete=jumpcnt=0;cdswitch=FALSE;
  124.         while(!delete&&ipc->command){
  125.            if(pending||selected(ipc))command(ipc);
  126.            if(jump){
  127.             jump=FALSE;
  128.             if(++jumpcnt>=JUMPLIMIT)ABORT2(INFLOOP,lnum);
  129.             ipc=ipc->u.link;}
  130.            else ipc++;}
  131.         if(pending)break;
  132.         /* we've now done all modification commands on the line */
  133.         PASS("execute(): output");
  134.         if (!nflag && !delete)  puts(linebuf);
  135.         /* if we've been set up for append, emit the text from it */
  136.         if (aptr > appends)readout();
  137.         PASS("execute(): end main loop");}
  138.     PASS("execute(): end execute");}
  139.  
  140. static int selected(ipc)
  141. sedcmd *ipc;
  142. /* is current command selected */
  143. {/*hh 10*/
  144.    char  *p1=ipc->addr1;
  145.    char  *p2=ipc->addr2;
  146.    int ans,first=FALSE;
  147.  
  148.    if(!p1)return !ipc->flags.allbut;
  149.    if( (ans=ipc->flags.inrange) != 0) ;    /* v1.4 */
  150.    else if (*p1 == CEND) ans=lastline;
  151.    else if (*p1==CLNUM)
  152.         first=ipc->flags.inrange=ans=lnum==linenum[*(unsigned char*)(p1+1)];
  153.    else first=ipc->flags.inrange=ans=match(p1, 0);
  154.    if ( ((ipc->flags.inrange&=(p2!=0)) != 0)
  155.         && (*p2!=CEND)
  156.       ) {
  157.       if(*p2==CLNUM)ipc->flags.inrange=(lnum<linenum[*(unsigned char*)(p2+1)]);
  158.       else if(*p2==CPLUS){
  159.       if(first) pcnt[p2[2]]=linenum[*(unsigned char*)(p2+1)];
  160.       ipc->flags.inrange=((--pcnt[p2[2]])>=0);}
  161.       else ipc->flags.inrange=!match(p2, 0);}
  162.    return ans^ipc->flags.allbut;}
  163.  
  164. /* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
  165. static int match(expbuf, gf)  char *expbuf;int gf;{/* gf set on recall */
  166.     char  c,  *p1=gf?bracend[0]:linebuf; int i;
  167.         for (i=1;i<MAXTAGS+1;i++)brastart[i]=bracend[i]=linebuf;
  168.     if(gf&&*expbuf) return FALSE; /*no repeats on anchored match*/
  169.     if (*expbuf++) {
  170.         brastart[0]= p1;
  171.         if (*expbuf==CCHR &&expbuf[1] != *p1) /* 1st char is wrong */
  172.             return (FALSE);        /* so fail */
  173.         return (advance(p1, expbuf));}    /* else try to match rest */
  174.     /* quick check for 1st character if it's literal */
  175.     if (*expbuf==CCHR) {c = expbuf[1];  /* get search character */
  176.         do { if (*p1 != c)continue;    /* scan the source string */
  177.              if (advance(brastart[0]=p1,expbuf)) /* match the rest */
  178.             return  1;
  179.             } while (*p1++);
  180.         return (FALSE);}    /* didn't find that first char */
  181.     /* else try for unanchored match of the pattern */
  182.     do {if (advance(brastart[0]=p1,expbuf))return  1;
  183.         } while (*p1++);
  184.     /* if got here, didn't match either way */
  185.     return (FALSE);}
  186.  
  187. /* attempt to advance match pointer by one pattern element */
  188. static int advance(lp, ep)  char *lp, *ep; {/* source, RE*/
  189.     char  *curlp;    /* save ptr for closures */
  190.     char   c;    /* scratch character holder */
  191.     char  *bbeg,*tep;
  192.     int    ct,i1,i2;    /* scratch integer holders */
  193.     while((c=*ep++)!=CEOF) switch(c){
  194.       case CCHR:            /* literal character */
  195.         if (*ep++ == *lp++) break;    /* if chars are equal */
  196.         return (FALSE);            /* else return false */
  197.       case CBOW:                    /*at the begining of a word*/
  198.            if(ISWCHAR(*lp)&&!ISWCHAR(lp[-1]))break; /*at word start*/
  199.            return (FALSE);
  200.       case CEOW:                    /*at the end of a word*/
  201.            if(!ISWCHAR(*lp)&&